package cn.miju.admin.system.service.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.jwt.JWTUtil;
import cn.hutool.jwt.RegisteredPayload;
import cn.miju.admin.framework.constant.AdminConstant;
import cn.miju.admin.framework.content.CodeMessage;
import cn.miju.admin.framework.exception.ServiceException;
import cn.miju.admin.system.service.LoginService;
import cn.miju.admin.system.vo.AccountLoginInVO;
import cn.miju.admin.system.vo.LoginOutVO;
import cn.miju.admin.system.vo.RegisterInVO;
import cn.miju.database.entity.SysOperLog;
import cn.miju.database.entity.SysRole;
import cn.miju.database.entity.SysUser;
import cn.miju.database.mapper.SysOperLogMapper;
import cn.miju.database.mapper.SysUserAuthRoleMapper;
import cn.miju.database.service.SysUserDataService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.collect.Maps;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * <pre>
 * 业务类
 * </pre>
 *
 * @author zhuming
 * @version 1.0.0
 * @since 2023-03-18 15:47
 */
@Service
@RequiredArgsConstructor
public class LoginServiceImpl implements LoginService {
    private final SysUserDataService sysUserDataService;
    private final SysUserAuthRoleMapper sysUserAuthRoleMapper;
    private final SysOperLogMapper sysOperLogMapper;

    /**
     * 用户登录
     * @param inVO {@link AccountLoginInVO}
     * @param clientIP IP
     * @return {@link LoginOutVO}
     */
    @Override
    public LoginOutVO login(AccountLoginInVO inVO, String clientIP) {
        SysUser sysUser = sysUserDataService.getOne(new LambdaQueryWrapper<SysUser>().
                eq(SysUser::getAccountNo, inVO.getAccountNo()));
        if (Objects.isNull(sysUser)) {
            throw new ServiceException(CodeMessage.LOGIN_USET_NOT_EXIT);
        }
        if (!Objects.equals(sysUser.getPassword(), inVO.getPassword())) {
            throw new ServiceException(CodeMessage.LOGIN_PASSWORD_FAIL);
        }
        DateTime now = DateTime.now();
        DateTime expireTime = now.offsetNew(DateField.SECOND, AdminConstant.JWT.TIMEOUT);
        Map<String, Object> payload = Maps.newHashMap();
        payload.put(RegisteredPayload.ISSUED_AT, now);
        payload.put(RegisteredPayload.EXPIRES_AT, expireTime);
        payload.put(RegisteredPayload.NOT_BEFORE, now);
        payload.put(AdminConstant.JWT.USER_INFO_KEY, sysUser);
        String token = JWTUtil.createToken(payload, AdminConstant.JWT.PRIVATE_KEY.getBytes(StandardCharsets.UTF_8));
        List<SysRole> roleList = sysUserAuthRoleMapper.getUserRoleList(sysUser.getId());
        List<String> roleCodeList = roleList.stream().map(SysRole::getRoleCode).collect(Collectors.toList());
        this.saveOperLog(clientIP, "登录", sysUser.getId());
        return LoginOutVO.builder().
                token(token).
                userInfo(LoginOutVO.UserInfo.builder().
                        dashboard(roleCodeList.contains("SA") ? "0" : "1").
                        userId(sysUser.getId()).
                        username(sysUser.getUsername()).
                        accountNo(sysUser.getAccountNo()).
                        sex(sysUser.getSex()).
                        mobile(sysUser.getMobile()).
                        email(sysUser.getEmail()).
                        signature(sysUser.getSignature()).
                        role(roleCodeList).
                        roleIds(roleList.stream().map(SysRole::getId).collect(Collectors.toList())).
                        build()).
                build();
    }

    /**
     * 用户注册
     *
     * @param inVO     {@link RegisterInVO}
     * @param clientIP IP
     */
    @Override
    public void register(RegisterInVO inVO, String clientIP) {
        SysUser sysUser = sysUserDataService.getOne(new LambdaQueryWrapper<SysUser>().
                eq(SysUser::getAccountNo, inVO.getAccountNo()));
        if (Objects.nonNull(sysUser)) {
            throw new ServiceException(CodeMessage.REGISTER_USET_EXIT);
        }
        sysUser = SysUser.builder().
                accountNo(inVO.getAccountNo()).
                password(inVO.getPassword()).
                username(inVO.getUsername()).
                sex(inVO.getSex()).
                mobile(inVO.getMobile()).
                email(inVO.getEmail()).
                signature(inVO.getSignature()).
                build();
        sysUserDataService.save(sysUser);
        this.saveOperLog(clientIP, "注册", sysUser.getId());
    }
    /**
     * 保存操作日志
     * @param clientIP 客户端IP
     * @param bizName 业务名称
     * @param userId 用户ID
     */
    private void saveOperLog(String clientIP, String bizName, Long userId) {
        CompletableFuture.runAsync(() -> sysOperLogMapper.insert(SysOperLog.builder().
                operDate(LocalDate.now()).
                userId(userId).
                bizName(bizName).
                ip(clientIP).
                build()));
    }
}
